<?php
/**
 * 定位后台服务器 - PHP版本
 * 支持WebSocket通信，接收位置上报和发送定位指令
 */

require __DIR__ . '/vendor/autoload.php';

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

// 配置
$config = [
    'host' => '0.0.0.0',
    'port' => 8080,
    'max_history_per_device' => 100
];

/**
 * WebSocket服务器类
 */
class LocationServer implements MessageComponentInterface {
    protected $clients;
    protected $devices;
    protected $deviceLocations;
    protected $locationHistory;
    protected $config;

    public function __construct($config) {
        $this->clients = new \SplObjectStorage;
        $this->devices = [];
        $this->deviceLocations = [];
        $this->locationHistory = [];
        $this->config = $config;
        
        echo "========================================\n";
        echo "定位后台服务器启动 (PHP版本)\n";
        echo "WebSocket地址: ws://{$config['host']}:{$config['port']}\n";
        echo "HTTP API地址: http://{$config['host']}:" . ($config['port'] + 1) . "\n";
        echo "========================================\n";
    }

    public function onOpen(ConnectionInterface $conn) {
        $this->clients->attach($conn);
        $conn->deviceId = null;
        
        echo "[" . date('Y-m-d H:i:s') . "] 新连接: {$conn->resourceId}\n";
        
        // 发送连接响应
        $conn->send(json_encode([
            'type' => 'connection_response',
            'data' => [
                'status' => 'connected',
                'sid' => $conn->resourceId,
                'message' => '连接成功'
            ]
        ]));
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        try {
            $data = json_decode($msg, true);
            
            if (!isset($data['type'])) {
                return;
            }

            switch ($data['type']) {
                case 'register_device':
                    $this->handleRegisterDevice($from, $data['data'] ?? []);
                    break;
                    
                case 'report_location':
                    $this->handleReportLocation($from, $data['data'] ?? []);
                    break;
                    
                case 'ping':
                    $from->send(json_encode([
                        'type' => 'pong',
                        'data' => ['timestamp' => date('c')]
                    ]));
                    break;
            }
        } catch (\Exception $e) {
            echo "处理消息错误: {$e->getMessage()}\n";
        }
    }

    public function onClose(ConnectionInterface $conn) {
        $this->clients->detach($conn);
        
        if ($conn->deviceId && isset($this->devices[$conn->deviceId])) {
            $deviceName = $this->devices[$conn->deviceId]['device_name'] ?? '未知设备';
            echo "[" . date('Y-m-d H:i:s') . "] 设备断开: {$deviceName} (ID: {$conn->deviceId})\n";
            unset($this->devices[$conn->deviceId]);
        }
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "错误: {$e->getMessage()}\n";
        $conn->close();
    }

    private function handleRegisterDevice(ConnectionInterface $conn, $data) {
        $deviceId = $conn->resourceId;
        $conn->deviceId = $deviceId;
        
        $this->devices[$deviceId] = [
            'device_id' => $deviceId,
            'device_name' => $data['device_name'] ?? '未知设备',
            'device_model' => $data['device_model'] ?? '',
            'android_version' => $data['android_version'] ?? '',
            'connected_at' => date('c'),
            'last_update' => date('c'),
            'connection' => $conn
        ];
        
        echo "[" . date('Y-m-d H:i:s') . "] 设备注册: {$this->devices[$deviceId]['device_name']} (ID: {$deviceId})\n";
        
        $conn->send(json_encode([
            'type' => 'register_response',
            'data' => [
                'success' => true,
                'device_id' => $deviceId,
                'message' => '设备注册成功'
            ]
        ]));
        
        // 广播设备上线
        $this->broadcast([
            'type' => 'device_connected',
            'data' => [
                'device_id' => $deviceId,
                'device_name' => $this->devices[$deviceId]['device_name'],
                'timestamp' => date('c')
            ]
        ], $conn);
    }

    private function handleReportLocation(ConnectionInterface $from, $data) {
        $deviceId = $from->deviceId;
        
        if (!$deviceId || !isset($this->devices[$deviceId])) {
            $from->send(json_encode([
                'type' => 'error',
                'data' => ['message' => '设备未注册']
            ]));
            return;
        }
        
        $locationData = [
            'latitude' => $data['latitude'] ?? 0,
            'longitude' => $data['longitude'] ?? 0,
            'accuracy' => $data['accuracy'] ?? 0,
            'timestamp' => $data['timestamp'] ?? date('c'),
            'address' => $data['address'] ?? '',
            'location_name' => $data['location_name'] ?? '',
            'is_simulated' => $data['is_simulated'] ?? false
        ];
        
        // 保存最新位置
        $this->deviceLocations[$deviceId] = $locationData;
        
        // 更新最后更新时间
        $this->devices[$deviceId]['last_update'] = date('c');
        
        // 添加到历史记录
        if (!isset($this->locationHistory[$deviceId])) {
            $this->locationHistory[$deviceId] = [];
        }
        
        $this->locationHistory[$deviceId][] = $locationData;
        
        // 只保留最近N条记录
        $maxHistory = $this->config['max_history_per_device'];
        if (count($this->locationHistory[$deviceId]) > $maxHistory) {
            $this->locationHistory[$deviceId] = array_slice(
                $this->locationHistory[$deviceId], 
                -$maxHistory
            );
        }
        
        $deviceName = $this->devices[$deviceId]['device_name'];
        echo "[" . date('Y-m-d H:i:s') . "] 收到位置上报 - {$deviceName}: ({$locationData['latitude']}, {$locationData['longitude']})\n";
        
        // 确认收到
        $from->send(json_encode([
            'type' => 'location_received',
            'data' => [
                'success' => true,
                'message' => '位置已接收',
                'timestamp' => date('c')
            ]
        ]));
        
        // 广播位置更新
        $this->broadcast([
            'type' => 'location_update',
            'data' => [
                'device_id' => $deviceId,
                'device_name' => $deviceName,
                'location' => $locationData
            ]
        ], $from);
    }

    private function broadcast($message, ConnectionInterface $exclude = null) {
        $jsonMessage = json_encode($message);
        
        foreach ($this->clients as $client) {
            if ($client !== $exclude) {
                $client->send($jsonMessage);
            }
        }
    }

    public function requestLocation($deviceId) {
        if (!isset($this->devices[$deviceId])) {
            return false;
        }
        
        $conn = $this->devices[$deviceId]['connection'];
        $conn->send(json_encode([
            'type' => 'request_location',
            'data' => [
                'timestamp' => date('c'),
                'message' => '请上报当前位置'
            ]
        ]));
        
        return true;
    }

    public function getDevices() {
        $devices = [];
        foreach ($this->devices as $deviceId => $device) {
            $deviceData = [
                'device_id' => $deviceId,
                'device_name' => $device['device_name'],
                'device_model' => $device['device_model'],
                'android_version' => $device['android_version'],
                'connected_at' => $device['connected_at'],
                'last_update' => $device['last_update']
            ];
            
            if (isset($this->deviceLocations[$deviceId])) {
                $deviceData['location'] = $this->deviceLocations[$deviceId];
            }
            
            $devices[] = $deviceData;
        }
        return $devices;
    }

    public function getDeviceHistory($deviceId) {
        return $this->locationHistory[$deviceId] ?? [];
    }
}

// 创建WebSocket服务器
$locationServer = new LocationServer($config);
$server = IoServer::factory(
    new HttpServer(
        new WsServer($locationServer)
    ),
    $config['port'],
    $config['host']
);

$server->run();


